//4.封装defineReactive函数，主要是为了对单个数据做数据劫持（数据劫持的核心代码）
function defineReactive(_data, key, value) {
  
  Object.defineProperty(_data, key, {
    get() {
      console.log("正在获取" + key + "的值", "收集所有依赖项watcher");
      return value;
    },
    set(newVal) {
      if (newVal === value) return;

      console.log("正在设置" + key + "的值", "通知所有的watcher进行更新");
      value = newVal;
    },
  });
}

//3. 封装一个Observer类，主要用来处理发布订阅模式的核心操作（响应式操作：收集依赖，通知更新）
class Observer {
  //构造器接受的是要被响应式处理的对象
  constructor(_data) {
    //把这个对象上放在实例上,将来在任何原型方法中都可以访问到这个实例上的数据
    this._data = _data;

    //判断当前的_data是对象还是数组
    if (Array.isArray(_data)) {
      this.observeArray(_data);
    } else {
      this.walk(_data);
    }
  }

  //在Observer的原型对象上封装一个对数组操作的方法
  observeArray(_data) {
    //当现在被操作的是数组的时候,我们不能直接使用defineProperty进行操作,但是我们要对数组内部的对象进行响应式操作
    _data.forEach((item) => {
      //把数组的值交给observe函数重新开始监听
      observe(item);
    });
  }

  //在Observer的原型对象上封装一个对对象操作的方法
  walk(_data) {
    for (let key of Object.keys(_data)) {
      //把每一个数据的响应式核心代码交给defineReactive函数处理
      defineReactive(_data, key, _data[key]);
    }
  }
}

//2.封装一个observe函数，接收_data,遍历_data的值，一个个的进行数据劫持
function observe(_data) {
  if (typeof _data !== "object" || _data === null) return;

  new Observer(_data);
}

//1. 封装一个Vue的构造函数
function Vue(options) {
  //把options配置对象内的data,放在实例对象this的_data属性上
  this._data = options.data;

  //【进行数据代理】,把_data中的属性取出来,一个个的放在vue实例上
  for (let key of Object.keys(this._data)) {
    Object.defineProperty(this, key, {
      get() {
        return this._data[key];
      },
      set(newVal) {
        this._data[key] = newVal;
      },
    });
  }

  //拿到_data的数据开始进行响应式操作，我们首先把响应式操作的代码放在observe函数中
  observe(this._data);
}

//实例化Vue
const vm = new Vue({
  data: {
    count: 1,
    course: {
      type: "easy",
      name: "vue",
    },
  },
});

console.log(vm);
function huoqu() {
  console.log(vm.count);
}

function shezhi() {
  vm.count++;
}

// huoqu();
// shezhi();
